﻿using System;
using MoveFramework_CS;
using System.Threading;

namespace MoveModel
{
    public class Move
    {
        #region Public variables

        public int Trigger
        {
            get
            {
                return trigger;
            }
            set
            {
                trigger = value;
            }
        }

        int trigger = 0;
        MoveWrapper.Quaternion or;

        public float Mx
        {
            get
            {
                return or.x;
            }
        }

        public float My
        {
            get
            {
                return or.y;
            }
        }

        public float Mz
        {
            get
            {
                return or.z;
            }
        }

        public float Mw
        {
            get
            {
                return or.w;
            }
        }

        MoveWrapper.Vector3 angAcc;

        public float Ax
        {
            get
            {
                return angAcc.x;
            }
        }

        public float Ay
        {
            get
            {
                return angAcc.y;
            }
        }

        public float Az
        {
            get
            {
                return angAcc.z;
            }
        }

        MoveWrapper.Vector3 pos;

        public double Radius
        {
            get
            {
                return applyCalibration(pos.z * 5 - 127.5);
            }
        }

        private double calibrationMin = 0.0;
        public void setCalibrationMin()
        {
            calibrationMin = this.Radius;
        }
        private double calibrationMax = 0.0;
        public void setCalibrationMax()
        {
            calibrationMax = this.Radius;
        }
        public bool calibrationDone = false;

        private double applyCalibration(double z)
        {
            if (!calibrationDone) return z;
            return 200 / (calibrationMax - calibrationMin) * (z - calibrationMax) + 100;
            //(100 - (-100)) / (max - min) * (z - max) + 100;
        }

        private double applyXYCalibration()
        {
            if (!calibrationDone) return 1;
            return 200 / (calibrationMax - calibrationMin);
        }

        //TODO: TRY IT OUT!!!!
        public double X
        {
            get
            {
                return Math.Round(pos.x * 5, 2) * applyXYCalibration();
            }
        }

        public double Y
        {
            get
            {
                return Math.Round(pos.y * 5, 2) * applyXYCalibration();
            }
        }

        public int Lr
        {
            get
            {
                return lr;
            }
            set
            {
                lr = value;
            }
        }

        public int Lg
        {
            get
            {
                return lg;
            }
            set
            {
                lg = value;
            }
        }

        public int Lb
        {
            get
            {
                return lb;
            }
            set
            {
                lb = value;
            }
        }

        int lr, lg, lb;
        private bool isShouldRender;

        public bool IsShouldRender
        {
            get
            {
                return isShouldRender;
            }
            set
            {
                isShouldRender = value;
            }
        }


        private bool isMoveButton = false;

        public bool IsMoveButton
        {
            get
            {
                return isMoveButton;
            }
        }

        private bool startDrawing = false;

        private bool isPSButton;

        public bool IsPSButton
        {
            get { return isPSButton; }
        }


        private int btnHoldTimerX = 0;
        private bool isCrossBtn = false;

        public bool IsCrossBtn
        {
            get
            {
                if (isCrossBtn)
                    if (btnHoldTimerX == 0)
                    {
                        btnHoldTimerX++;
                        return true;
                    }
                    else
                    {
                        if (btnHoldTimerX > 10)
                        {
                            return true;
                        }
                        btnHoldTimerX++;
                        return false;
                    }
                else
                {
                    btnHoldTimerX = 0;
                    return false;
                }
            }
        }

        private int btnHoldTimerC = 0;
        private bool isCircleBtn = false;

        public bool IsCircleBtn
        {
            get
            {
                if (isCircleBtn)
                    if (btnHoldTimerC == 0)
                    {
                        btnHoldTimerC++;
                        return true;
                    }
                    else
                    {
                        if (btnHoldTimerC > 10)
                        {
                            return true;
                        }
                        btnHoldTimerC++;
                        return false;
                    }
                else
                {
                    btnHoldTimerC = 0;
                    return false;
                }
            }
        }

        private bool isSelectBtn = false;

        public bool IsSelectBtn
        {
            get
            {
                return isSelectBtn;
            }
        }

        private int btnHoldTimerS = 0;
        private bool isSquareBtn = false;

        public bool IsSquareBtn
        {
            get
            {
                if (isSquareBtn)
                    if (btnHoldTimerS == 0)
                    {
                        btnHoldTimerS++;
                        return true;
                    }
                    else
                    {
                        if (btnHoldTimerS > 10)
                        {
                            return true;
                        }
                        btnHoldTimerS++;
                        return false;
                    }
                else
                {
                    btnHoldTimerS = 0;
                    return false;
                }
            }
        }

        private int btnHoldTimerT = 0;
        private bool isTriangleBtn = false;

        public bool IsTriangleBtn
        {
            get
            {

                if (isTriangleBtn)
                    if (btnHoldTimerT == 0)
                    {
                        btnHoldTimerT++;
                        return true;
                    }
                    else
                    {
                        if (btnHoldTimerT > 10)
                        {
                            return true;
                        }
                        btnHoldTimerT++;
                        return false;
                    }
                else
                {
                    btnHoldTimerT = 0;
                    return false;
                }
            }
        }

        private bool isStartBtn = false;

        public bool IsStartBtn
        {
            get
            {
                return isStartBtn;
            }
        }

        #endregion

        public Move()
        {
            MoveWrapper.init();

            int moveCount = MoveWrapper.getMovesCount();

            if (moveCount > 0)
            {
                pos = MoveWrapper.getPosition(0);
                or = MoveWrapper.getOrientation(0);
                angAcc = new MoveWrapper.Vector3();
                angAcc.x = 0;
                angAcc.y = 0;
                angAcc.z = 0;
                angAcc = MoveWrapper.getAngularAcceleration(0);
                trigger = MoveWrapper.getTriggerValue(0);
                MoveWrapper.setRumble(0, 255);
                Thread.Sleep(40);
                MoveWrapper.setRumble(0, 0);
            }
            else
            {
                Console.WriteLine("No move controller detected");
                //Console.ReadKey();
                System.Environment.Exit(0);
            }

            MoveWrapper.subscribeMoveUpdate(MoveUpdateCallback, MoveKeyDownCallback, MoveKeyUpCallback, NavUpdateCallback, NavKeyDownCallback, NavKeyUpCallback);
            isShouldRender = true;
        }

        ~Move()
        {
            MoveWrapper.unsubscribeMove();
        }

        private ReaderWriterLock rwLock = new ReaderWriterLock();

        private MoveWrapper.Vector3 prevPos = new MoveWrapper.Vector3();

        void MoveUpdateCallback(int id, MoveWrapper.Vector3 position, MoveWrapper.Quaternion orientation, MoveWrapper.Vector3 angularAcceleration, int t)
        {
            prevPos = pos;


            trigger = t;
            MoveWrapper.setRumble(id, Trigger);
            or = orientation;
            pos = position;
            angAcc = angularAcceleration;

            startDrawing = Trigger > 0;

            isMoveButton = MoveWrapper.getButtonState(id, MoveButton.B_MOVE);
            isCrossBtn = MoveWrapper.getButtonState(id, MoveButton.B_CROSS);
            isCircleBtn = MoveWrapper.getButtonState(id, MoveButton.B_CIRCLE);
            isSquareBtn = MoveWrapper.getButtonState(id, MoveButton.B_SQUARE);
            isTriangleBtn = MoveWrapper.getButtonState(id, MoveButton.B_TRIANGLE);
            isSelectBtn = MoveWrapper.getButtonState(id, MoveButton.B_SELECT);
            isStartBtn = MoveWrapper.getButtonState(id, MoveButton.B_START);
            isPSButton = MoveWrapper.getButtonState(id, MoveButton.B_PS);
        }

        #region callback methods not working in this framework version
        void MoveKeyUpCallback(int id, int keyCode) { }
        void MoveKeyDownCallback(int id, int keyCode) { }
        void NavUpdateCallback(int id, int trigger1, int trigger2, int stickX, int stickY) { }
        void NavKeyUpCallback(int id, int keyCode) { }
        void NavKeyDownCallback(int id, int keyCode) { }
        #endregion
    }
}
